# Create your views here.
from django.shortcuts import render_to_response
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, HttpResponse
import django.newforms as forms
from hakaze.forums.models import *
from hakaze.utils.templatetags.hakaze_filters import hakazefy
from django.template import RequestContext
from django.contrib.auth.models import User
from django.contrib.auth import login,authenticate,logout
from django.utils import feedgenerator
from django.template.defaultfilters import escape,linebreaksbr,urlize
from hakaze import settings
from django.views.decorators.vary import vary_on_cookie

def gen_contextdata():
    """
       This method will generate a dictionary for storing
       inside the session context
    """
    tdict = {}
    catlist = Category.objects.all().order_by('priority')
    tdict['categories'] = catlist
    tdict['tsettings'] = settings.TEMPLATE_VARS
    return tdict

def gen_nslist(ns='empty',withblank=False):
    l = []
    if withblank:
       l.append((0,'--------'))
    if ns == 'empty':
       ns = Channel.objects.filter(parent__isnull=True)
    for n in ns:
       ls = []
       for i in n.get_path():
           ls.insert(0,i.name)
       l.append((n.id,"::".join(ls)))
       l.extend(gen_nslist(n.channel_set.all()))
    return l


class FooterBlock:
    def __init__(self,title):
        self.title = title
        self.items = []

    def add_item(self,url,description):
        self.items.append((url,description))



class NewPostForm(forms.Form):
    """
       Class to generate forms for new posts
    """
    name = forms.CharField(max_length=50,required=False,widget=forms.widgets.Input(attrs={'class':'entryshort'}))
    link = forms.CharField(max_length=50,required=False,widget=forms.widgets.Input(attrs={'class':'entryshort'}))
    contents = forms.CharField(widget=forms.widgets.Textarea(attrs={'class' : 'entrywide' }))
    formtype = forms.CharField(widget=forms.widgets.HiddenInput(),initial='postform')

class NewCategoryForm(forms.Form):
    """
       Class to generate formsfor new categories
    """
    name = forms.CharField(max_length=50,widget=forms.widgets.Input(attrs={'class':'entryshort'}))
    formtype = forms.CharField(widget=forms.widgets.HiddenInput(),initial='catform')
    priority = forms.IntegerField(initial=5)

class NewChannelForm(forms.Form):
    """
       Class to generate formsfor new channels
    """
    codename = forms.CharField(max_length=50,widget=forms.widgets.Input(attrs={'class':'entryshort'}))
    name = forms.CharField(max_length=128,widget=forms.widgets.Input(attrs={'class':'entryshort'}))
    description = forms.CharField(widget=forms.widgets.Textarea(attrs={'class':'entrywide'}))
    formtype = forms.CharField(widget=forms.widgets.HiddenInput(),initial='nsform')
    category = forms.CharField(widget=forms.widgets.Select(attrs={'class':'entryselect'}))
    priority = forms.IntegerField(initial=5)

    def __init__(self, *args , **kwargs ):
        super(NewChannelForm,self).__init__(*args,**kwargs)
        self.fields['category'].widget=forms.widgets.Select(choices=self.gen_catlist())

    def gen_catlist(self):
        l = []
        for c in Category.objects.all():
            l.append((c.name,c.name))
        return l

class NewThreadForm(NewPostForm):
    """
       A meta class for generating forms for new threads
       We need this to properly align form
    """
    title = forms.CharField(label="Thread Title",max_length=128,widget=forms.widgets.Input(attrs={'class':'entryshort'}))
    formtype = forms.CharField(widget=forms.widgets.HiddenInput(),initial='threadform')

class LoginForm(forms.Form):
    username = forms.CharField(max_length=128)
    password = forms.CharField(max_length=128,widget=forms.widgets.PasswordInput())

@vary_on_cookie
def channellist(response):
    """
       get all channel lists and display it
    """
    tdict = {}
    return render_to_response('forums/boardindex.html',tdict,context_instance=RequestContext(response, gen_contextdata()))

@vary_on_cookie
def channelview(response,ns_name):
    """
       get latest threads and posts in channel ns_name and display it
    """
    tdict = {}
    ns_name = ns_name.lower()
    if response.POST:
       tdict['notice_messages'] = notices = []
       tdict['threadform'] = f = NewThreadForm(response.POST)
       if f.is_valid():
          if response.POST['submit'].lower() == 'preview':
             p = Post(link=f.clean_data['link'],ip=response.META['REMOTE_ADDR'],contents=f.clean_data['contents'])
             p.set_poster(f.clean_data['name'])
             try:
                p.http_x_forwarded_for = response.META['HTTP_X_FORWARDED_FOR']
             except:
                pass
             tdict['post'] = p
             notices.append('Previewing Post')
             return render_to_response('forums/postpreview.html',tdict,context_instance=RequestContext(response, gen_contextdata()))
          t = Thread(title=f.clean_data['title'])
          t.channel = Channel.objects.get(codename=ns_name)
          t.save()
          p = Post(link=f.clean_data['link'],ip=response.META['REMOTE_ADDR'],contents=f.clean_data['contents'])
          p.set_poster(f.clean_data['name'])
          try:
             p.http_x_forwarded_for = response.META['HTTP_X_FORWARDED_FOR']
          except: 
             pass
          p.thread = t
          p.save()
          tdict['threadform'] = NewThreadForm()
          notices.append('Thread created')
          tdict['pagerefresh'] = {'timeout':5}
          return render_to_response('refresh.html',tdict,context_instance=RequestContext(response, gen_contextdata()))

    tdict['channel'] = ns = Channel.objects.get(codename=ns_name)
    tdict['childs'] = ns.channel_set.all()
    tdict['newthreads'] = ns.get_newthreadposts()
    tdict['postform'] = NewPostForm()
    if not tdict.has_key('threadform'): tdict['threadform'] = NewThreadForm()
    return render_to_response('forums/channelview.html',tdict,context_instance=RequestContext(response, gen_contextdata()))

@vary_on_cookie
def threadview(response,ns_name,t_id,page=1,pagesize=20):
    """
       get thread posts and display it according to page, pagesize etc .
    """
    from math import ceil
    tdict = {}
    if response.POST:
        tdict['notice_messages'] = notices = []
        tdict['postform'] = f = NewPostForm(response.POST)
        if f.is_valid():
            t = Channel.objects.get(codename=ns_name).get_thread(t_id)
            p = Post(link=f.clean_data['link'],ip=response.META['REMOTE_ADDR'],contents=f.clean_data['contents'])
            p.set_poster(f.clean_data['name'])
            try:
               p.http_x_forwarded_for = response.META['HTTP_X_FORWARDED_FOR']
            except:
               pass
            p.thread = t
            if response.POST['submit'].lower() == 'preview':
               tdict['post'] = p
               return render_to_response('forums/postpreview.html',tdict,context_instance=RequestContext(response, gen_contextdata()))
            p.save()
            tdict['postform'] = NewPostForm()
            notices.append('Post submitted')
            tdict['pagerefresh'] = {'timeout':5}
            return render_to_response('refresh.html',tdict,context_instance=RequestContext(response, gen_contextdata()))

    tdict['channel'] = n = Channel.objects.get(codename=ns_name)
    tdict['thread'] = t = n.get_thread(t_id)
    try:
       pagesize = int(pagesize)
    except:
       pagesize = 20
    if not tdict.has_key('postform'): tdict['postform'] = f = NewPostForm()
    tdict['pagerange'] = range(1,int(ceil(float(tdict['thread'].post_set.count()) / float(pagesize)))+1)
    if str(page).lower() == "last":
       page = tdict['pagerange'][-1] - 1
    else:
       try:
         page = int(page) - 1
       except:
         page = 0
    start = (page * pagesize)
    posts = tdict['thread'].post_set.all().order_by('datetime')[start:(start+pagesize)]
    tdict['posts'] = posts
    tdict['page'], tdict['pagesize'] = page + 1, pagesize
    return render_to_response('forums/threadview.html', tdict,context_instance=RequestContext(response, gen_contextdata()))

@vary_on_cookie
def postview(response,ns_name,t_id,post_id):
    """
       view individual posts
    """
    tdict = {}
    tdict['post'] = Channel.objects.get(codename=ns_name).get_thread(t_id).get_post(post_id)
    tdict['postform'] = NewPostForm()
    return render_to_response('forums/postview.html',tdict,context_instance=RequestContext(response, gen_contextdata()))

@vary_on_cookie
def loginview(response):
    tdict = {}
    if response.user.is_authenticated():
       return HttpResponseRedirect(reverse('hakaze.forums.views.adminview'))
    if response.POST:
        tdict['notice_messages'] = notices = []
        tdict['loginform'] = f = LoginForm(response.POST)
        if f.is_valid():
           user = authenticate(username=f.clean_data['username'],password=f.clean_data['password'])
           try:
             login(response,user)
             return HttpResponseRedirect(reverse('hakaze.forums.views.adminview'))
           except:
             notices.append('Invalid Login')
    if not tdict.has_key('loginform'): tdict['loginform'] = LoginForm()
    return render_to_response('loginview.html',tdict,context_instance=RequestContext(response, gen_contextdata()))

@vary_on_cookie
def logoutview(response):
    logout(response)
    return HttpResponseRedirect(reverse('hakaze.forums.views.channellist'))

def directtoforums(response):
    return HttpResponseRedirect(reverse('hakaze.forums.views.channellist'))


############################
'''

Feed Generators

'''
###########################

@vary_on_cookie
def feed_thread_latestposts(response,ns_name,t_id,feedtype):
    fg = None
    thread = Channel.objects.get(codename=ns_name).get_thread(t_id)
    if feedtype == "atom1" or feedtype == "html":
       fg = feedgenerator.Atom1Feed(title=thread.title,
                                   link=reverse('hakaze.forums.views.threadview',args=[ns_name,t_id]),
                                   description="Feed thread /%s/%s/" % (ns_name,t_id),
                                   )
    if fg:
       for p in thread.getlatestposts(count=15):
           fg.add_item(title=thread.title,
                       link=reverse('hakaze.forums.views.postview',args=[ns_name,t_id,p.get_idinthread()]),
                       description=hakazefy(p.contents,thread),
                       author_name=escape(u"%s:%s" % (p.get_name(),p.get_tripcode())),
                       pubdate=p.datetime,
                       )
       if feedtype != "html":
           return HttpResponse(fg.writeString('utf-8'))
       else:
           tdict = {
           'feedgenerator' : fg,
           'pagerefresh' : { 'timeout' : 60 },
           }
           return render_to_response("forums/html_feed.html",tdict,context_instance=RequestContext(response, gen_contextdata()))
    return HttpResponse('No such feed type')

@vary_on_cookie
def feed_all_latestposts(response,feedtype):
    fg = None
    posts = Post.objects.order_by('-datetime')[:20]
    if feedtype == "atom1" or feedtype == "html":
       fg = feedgenerator.Atom1Feed(title='Latest Posts',
                                   link=reverse('hakaze.forums.views.channellist'),
                                   description="Latest Posts",
                                   )
    if fg:
       for p in posts:
           fg.add_item(title=p.thread.title,
                       link=reverse('hakaze.forums.views.postview',
                                    args=[p.thread.channel.codename,
                                          p.thread.get_idinchannel(),
                                          p.get_idinthread()]),
                       description=hakazefy(p.contents,p.thread),
                       author_name=escape(u"%s:%s" % (p.get_name(),p.get_tripcode())),
                       pubdate=p.datetime,
                       )
       if feedtype != "html":
           return HttpResponse(fg.writeString('utf-8'))
       else: 
           tdict = {
           'feedgenerator' : fg,
           'pagerefresh' : { 'timeout' : 60 },
           }
           return render_to_response("forums/html_feed.html",tdict,context_instance=RequestContext(response, gen_contextdata()))
    return HttpResponse('No such feed type')  

@vary_on_cookie
def feed_channel_latestposts(response,ns_name,feedtype):
    fg = None
    posts = Post.objects.filter(thread__channel__codename=ns_name).order_by('-datetime')[:20]
    if feedtype == "atom1" or feedtype == "html":
       fg = feedgenerator.Atom1Feed(title="Latest Posts From %s" % ns_name,
                                   link=reverse('hakaze.forums.views.channellist'),
                                   description="Latest Posts From %s" % ns_name,
                                   )
    if fg:
       for p in posts:
           fg.add_item(title=p.thread.title,
                       link=reverse('hakaze.forums.views.postview',
                                    args=[p.thread.channel.codename,
                                          p.thread.get_idinchannel(),
                                          p.get_idinthread()]),
                       description=hakazefy(p.contents,p.thread),
                       author_name=escape(u"%s:%s" % (p.get_name(),p.get_tripcode())),
                       pubdate=p.datetime,
                       )
       if feedtype != "html":
           return HttpResponse(fg.writeString('utf-8'))
       else:
           tdict = {
           'feedgenerator' : fg,
           'pagerefresh' : { 'timeout' : 60 },
           }
           return render_to_response("forums/html_feed.html",tdict,context_instance=RequestContext(response, gen_contextdata()))
    return HttpResponse('No such feed type')

@vary_on_cookie
def feed_channel_latestthreads(response,ns_name,feedtype):
    fg = None
    threads = Thread.objects.filter(channel__codename=ns_name).order_by('-datecreated')[:20]
    if feedtype == "atom1" or feedtype == "html":
       fg = feedgenerator.Atom1Feed(title="Latest Threads From %s" % ns_name,
                                   link=reverse('hakaze.forums.views.channellist'),
                                   description="Latest Threads From %s" % ns_name,
                                   )
    if fg:
       for thread in threads:
          posts = thread.getfirstpost()
          for p in posts:
               fg.add_item(title=p.thread.title,
                           link=reverse('hakaze.forums.views.threadview',
                                          args=[p.thread.channel.codename,
                                                p.thread.get_idinchannel(),
                                                "last"]),
                           description=hakazefy(p.contents,p.thread),
                           author_name=escape(u"%s:%s" % (p.get_name(),p.get_tripcode())),
                           pubdate=p.datetime,
                           )
       if feedtype != "html":
           return HttpResponse(fg.writeString('utf-8'))
       else:
           tdict = {
           'feedgenerator' : fg,
           'pagerefresh' : { 'timeout' : 60 },
           }
           return render_to_response("forums/html_feed.html",tdict,context_instance=RequestContext(response, gen_contextdata()))
    return HttpResponse('No such feed type')

@vary_on_cookie
def feed_all_latestthreads(response,feedtype):
    fg = None
    threads = Thread.objects.order_by('-datecreated')[:20]
    if feedtype == "atom1" or feedtype == "html":
       fg = feedgenerator.Atom1Feed(title="Latest Threads",
                                   link=reverse('hakaze.forums.views.channellist'),
                                   description="Latest Threads",
                                   )
    if fg:
       for thread in threads:
          posts = thread.getfirstpost()
          for p in posts:
               fg.add_item(title=p.thread.title,
                           link=reverse('hakaze.forums.views.threadview',
                                          args=[p.thread.channel.codename,
                                                p.thread.get_idinchannel(),
                                                "last"]),
                           description=hakazefy(p.contents,p.thread),
                           author_name=escape(u"%s:%s" % (p.get_name(),p.get_tripcode())),
                           pubdate=p.datetime,
                           )
       if feedtype != "html":
           return HttpResponse(fg.writeString('utf-8'))
       else:
           tdict = {
           'feedgenerator' : fg,
           'pagerefresh' : { 'timeout' : 60 },
           }
           return render_to_response("forums/html_feed.html",tdict,context_instance=RequestContext(response, gen_contextdata()))
    return HttpResponse('No such feed type')


######################################
'''

Administrator/Staff 
Control Panel

'''
######################################

class NewUserForm(forms.Form):
    username = forms.CharField(max_length=128)
    password = forms.CharField(max_length=128,widget=forms.widgets.PasswordInput())
    cpassword = forms.CharField(label='Confirm Password',max_length=128,widget=forms.widgets.PasswordInput()) 
    email = forms.EmailField()
    is_staff = forms.BooleanField()
    formtype = forms.CharField(widget=forms.widgets.HiddenInput(),initial='userform')


class ChangePasswordForm(forms.Form):
    password = forms.CharField(max_length=128,widget=forms.widgets.PasswordInput())
    cpassword = forms.CharField(label='Confirm Password',max_length=128,widget=forms.widgets.PasswordInput())
    formtype = forms.CharField(widget=forms.widgets.HiddenInput(),initial='cpwdform')


class EditChannelForm(NewChannelForm):
    origcodename = forms.CharField(widget=forms.widgets.HiddenInput())

    def __init__(self, *args , **kwargs ):
        super(EditChannelForm,self).__init__(*args,**kwargs)

    def gen_codenamelist(self):
        l = []
        for c in Channel.objects.all().values('codename'):
            l.append((c['codename'],c['codename']))
        return l

class EditCategoryForm(NewCategoryForm):
    id = forms.IntegerField(widget=forms.widgets.HiddenInput())

    def __init__(self, *args , **kwargs ):
        super(EditCategoryForm,self).__init__(*args,**kwargs)

    def gen_catlist(self):
        l = []
        for c in Category.objects.all().values('name'):
            l.append((c['name'],c['name']))
        return l





def adminview(response):
    if not response.user.is_authenticated():
       return HttpResponseRedirect(reverse('hakaze.forums.views.loginview'))
    tdict = {}
    if response.POST:
       tdict['notice_messages'] = notices = []
       ftype = response.POST['formtype']
       if ftype == 'nsform': tdict[ftype] = f = NewChannelForm(response.POST)
       elif ftype == 'catform': tdict[ftype] = f = NewCategoryForm(response.POST)
       elif ftype == 'userform' : tdict[ftype] = f = NewUserForm(response.POST)
       elif ftype == 'cpwdform' : tdict[ftype] = f = ChangePasswordForm(response.POST)
       if f.is_valid():
          if ftype == 'nsform':
             n = Channel(name=f.clean_data['name'],
                           description=f.clean_data['description'],
                           category=Category.objects.get(name=f.clean_data['category']),
                           priority=int(f.clean_data['priority']),
                           )
             n.set_codename(f.clean_data['codename'])
             n.save()
             tdict[ftype] = NewChannelForm()
             notices.append('Channel Created')
          elif ftype == 'catform':
             c = Category(name=f.clean_data['name'],priority=int(f.clean_data['priority']))
             c.save()
             tdict[ftype] = NewCategoryForm()
             notices.append('Category Created')
          elif ftype == 'userform':
             if f.clean_data['password'] == f.clean_data['cpassword']:
                u = User.objects.create_user(f.clean_data['username'],f.clean_data['email'],f.clean_data['password'])
                u.is_staff = f.clean_data['is_staff']
                u.save()
                tdict[ftype] = NewUserForm()
                notices.append('User Created')
             else:
                notices.append('Passwords Does Not Match')
          elif ftype == 'cpwdform':
             if f.clean_data['password'] == f.clean_data['cpassword']:
                response.user.set_password(f.clean_data['password'])
                response.user.save()
                logout(response)
                tdict[ftype] = ChangePasswordForm()
                notices.append('Password Changed')
             else:
                notices.append('Passwords Does Not Match')
    if not tdict.has_key('cpwdform'): tdict['cpwdform'] = ChangePasswordForm()
    if not tdict.has_key('userform'): tdict['newuserform'] = NewUserForm()
    if not tdict.has_key('editcatform'): tdict['editcatform'] = EditCategoryForm()
    if not tdict.has_key('editnsform'): tdict['editnsform'] = EditChannelForm()
    if not tdict.has_key('nsform'): tdict['nsform'] = NewChannelForm()
    if not tdict.has_key('catform'): tdict['catform'] = NewCategoryForm()
    return render_to_response('adminview.html',tdict,context_instance=RequestContext(response, gen_contextdata()))


def admineditview(response,type):
    if not response.user.is_authenticated():
       return HttpResponseRedirect(reverse('hakaze.forums.views.loginview'))
    tdict = {}
    if type == 'category':
       if response.POST:
          tdict['notice_messages'] = notices = []
          tdict['editcatform'] = f = EditCategoryForm(response.POST)
          if f.is_valid():
             c = Category.objects.get(id=int(f.clean_data['id']))
             c.name = f.clean_data['name']
             c.priority = int(f.clean_data['priority'])
             c.save()
             notices.append('Category Edited')
             tdict['pagerefresh'] = {'timeout':5}
             return render_to_response('refresh.html',tdict,context_instance=RequestContext(response, gen_contextdata()))
       try:
          id = response.GET['id']
          tdict['category'] = c = Category.objects.get(id=int(id))
          if not tdict.has_key('editcatform'):
             data = { 'id' : c.id,
                      'name' : c.name,
                      'priority' : c.priority,}
             tdict['editcatform'] = EditCategoryForm(initial=data)
       except KeyError:
          tdict['catlist'] = Category.objects.all()
       if not tdict.has_key('editcatform'): tdict['editcatform'] = EditCategoryForm()

    if type == 'channel':
       if response.POST:
          tdict['notice_messages'] = notices = []
          tdict['editnsform'] = f = EditChannelForm(response.POST)
          if f.is_valid():
             n = Channel.objects.get(codename=f.clean_data['origcodename'])
             n.name=f.clean_data['name']
             n.description=f.clean_data['description']
             n.category=Category.objects.get(name=f.clean_data['category'])
             n.priority=int(f.clean_data['priority'])
             n.save()
             notices.append('Channel Edited')
             tdict['pagerefresh'] = {'timeout':5}
             return render_to_response('refresh.html',tdict,context_instance=RequestContext(response, gen_contextdata()))
       try: 
          codename = response.GET['codename']
          tdict['channel'] = n = Channel.objects.get(codename=codename)
          if not tdict.has_key('editnsform'):
             data = { 'origcodename' : n.codename,
                      'codename' : n.codename,
                      'name' : n.name,
                      'description' : n.description,
                      'category' : n.category,
                      'priority' : n.priority,}
             tdict['editnsform'] = f = EditChannelForm(initial=data)
       except KeyError:
          tdict['nslist'] = Channel.objects.all()
    return render_to_response('admin_editview.html',tdict, context_instance=RequestContext(response, gen_contextdata()))

def postdelete(response):
    if not response.user.is_authenticated():
       return HttpResponseRedirect(reverse('hakaze.forums.views.loginview'))
    if response.GET:
       try:
           p = Post.objects.get(id=int(response.GET['postid']))
           try:
              undelete = int(response.GET['undelete'])
              if undelete == 1:
                 p.is_deleted = False
                 p.save()
                 return HttpResponse('Post unmarked from deleted')
           except KeyError:
              p.is_deleted = True
              p.save()
              return HttpResponse('Post marked as deleted')
       except KeyError:
           pass
    return HttpResponse('Invalid input')
